﻿using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace WpfApplication1.Connections
{
    public class UdpServer
    {
        private static int LISTEN_PORT = 5500;
        private static int SENDER_PORT = 5501;
        private static string SENDER_IP = "192.168.0.39";
        private static string LISTEN_IP = "192.168.0.39";
        private Controllers.IController controller;
        private UdpState udpStateListener;
        private UdpClient udpSender;
        private Boolean receiving = false; //true when we are listening/receiving on udpclient
        private Stopwatch stopwatch;
        private double samplingTime;
        private double samplingTimeOld = 1;

        public UdpServer(Controllers.IController controller)
        {
            this.controller = controller;
            stopwatch = new Stopwatch();
        }

        public void ReceiveCallback(IAsyncResult ar)
        {
            if (receiving)
            {
                try
                {
                    UdpState tempUdpStateListener = (UdpState)(ar.AsyncState);

                    Byte[] receiveBytes = tempUdpStateListener.udpClient.EndReceive(ar, ref tempUdpStateListener.ipEndPoint);
                    String receiveString = Encoding.ASCII.GetString(receiveBytes);

                    //Console.WriteLine("Received: {0}", receiveString);
                    //Console.WriteLine("PMR-Info: Packet received");
                    //Console.WriteLine("PMR-Info: Start modulation");

                    stopwatch.Stop();
                    //Console.WriteLine("Server: " + stopwatch.ElapsedMilliseconds);
                    samplingTime = stopwatch.ElapsedMilliseconds;
                    samplingTime = samplingTime / 1000;
                    if (samplingTime == 0)
                    {
                        samplingTime = samplingTimeOld;
                    }
                    else
                    {
                        samplingTimeOld = samplingTime;
                    }
                    
                    //achtung test only
                    samplingTime = 0.015;
                    //test fertig

                    String aircraftInputs = controller.processUdpMessage(receiveString, samplingTime);
                    stopwatch.Restart();

                    if (!controller.MODULATING_PAUSED)
                    {
                        Byte[] sendBytes = Encoding.ASCII.GetBytes(aircraftInputs);
                        udpSender.Send(sendBytes, sendBytes.Length);
                    }

                    tempUdpStateListener.udpClient.BeginReceive(new AsyncCallback(ReceiveCallback), tempUdpStateListener);

                }
                catch (SocketException e)
                {
                    // Oups, connection was closed
                    Console.WriteLine("PMR-Error: UDPConnection is closed");
                }
                catch (ObjectDisposedException e)
                {
                    // Oups, client was disposed
                    Console.WriteLine("PMR-Error: UDPConnectoin is disposed");
                }
            }
        }

        public void startUdpClients()
        {
            // Receive a message and write it to the console.
            try
            {
                //UDP Listener
                udpStateListener = new UdpState();
                udpStateListener.ipEndPoint = new IPEndPoint(IPAddress.Parse(LISTEN_IP), LISTEN_PORT);
                udpStateListener.udpClient = new UdpClient();
                udpStateListener.udpClient.ExclusiveAddressUse = false;

                //test
                udpStateListener.udpClient.Client.ExclusiveAddressUse = false;
                //endtest

                udpStateListener.udpClient.Client.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, System.Net.Sockets.SocketOptionName.ReuseAddress, true);
                udpStateListener.udpClient.Client.Bind(udpStateListener.ipEndPoint);

                Console.WriteLine("listening for messages");
                receiving = true;
                udpStateListener.udpClient.BeginReceive(new AsyncCallback(ReceiveCallback), udpStateListener);

                stopwatch.Start();

                //UDP Sender
                udpSender = new UdpClient(SENDER_IP, SENDER_PORT);

            }
            catch (Exception e)
            {
                Console.WriteLine("The following error occurred:");
                Console.WriteLine(e.Message);   // Print the error message.
                Console.WriteLine(e.Source);    // Name of application or object that caused the error.
                Console.WriteLine(e.StackTrace); //String that contains the stack trace for this exception.
            }

        }

        public void terminateUdpServer()
        {
            receiving = false;
            if (udpStateListener.udpClient != null)
            {
                udpStateListener.udpClient.Close();
            }
            if (udpSender != null)
            {
                udpSender.Close();
            }
        }
    }
}
